const expressJSDocSwagger = require("express-jsdoc-swagger");
const OpenApiValidator = require("express-openapi-validator");
const {
  ActionError,
  PathError,
  MethodsError,
} = require("../CustomError.class");
const RE = {
  username: /^[\w-]{4,16}$/,
  email:
    /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
  password:
    /^\S*(?=\S{6,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/,
  phone: /^(?:(?:\+|00)86)?1[3-9]\d{9}$/,
  path: /^(\/[^\/]+)+$/,
};

/* 配置项 */
module.exports = ({ server, env }) => {
  const options = {
    info: {
      version: "1.0.0",
      title: "In YanCheng API 接口",
      description: "In YanCheng API 接口",
    },

    servers: [
      {
        url: `http://${env.SERVER_HOST}:${env.SERVER_PORT}${env.ROUTE_BASE_PATH}`,
      },
    ],

    security: {
      auth: {
        type: "apiKey",
        in: "header",
        name: "authorization",
      },
    },
    baseDir: __dirname,
    filesPattern: ["../routes/**/*.js"],
    // exposeSwaggerUI: true,
    swaggerUIPath: `${env.ROUTE_BASE_PATH}${env.SWAGGER_UI_PATH}`,
    // notRequiredAsNullable: false,
    // multiple: true,
  };

  return new Promise((resolve, reject) => {
    const instance = expressJSDocSwagger(server)(options);
    instance.on("finish", (apiSpec) => {
      // 验证请求
      server.use(
        OpenApiValidator.middleware({
          apiSpec,
          validateRequests: true, // (default)
          validateResponses: false, // false by default
          // 自定义验证规则
          formats: [
            {
              name: "_username",
              type: "string",
              validate: (v) => RE.username.test(v),
              // validate: (v) => true,
            },
            {
              name: "_password",
              type: "string",
              validate: (v) => RE.password.test(v),
              // validate: (v) => true,
            },
            {
              name: "_email",
              type: "string",
              validate: (v) => RE.email.test(v),
              // validate: (v) => true,
            },
            {
              name: "_phone",
              type: "string",
              validate: (v) => RE.phone.test(v),
              // validate: (v) => true,
            },
            {
              name: "_action",
              type: "string",
              validate: (v) => {
                if (!["*", "allow", "deny"].includes(v)) {
                  throw new ActionError(`[*, allow, deny]`);
                } else {
                  return true;
                }
              },
            },
            {
              name: "_methods",
              type: "string",
              validate: (v) => {
                if (v !== "*") throw new MethodsError();
                return true;
              },
            },
            
            {
              name: "_path",
              type: "string",
              validate: (v) => {
                if (!RE.path.test(v)) throw new PathError();
                return true;
              },
            },
          ],
        })
      );
      resolve();
    });

    instance.on("error", (error) => {
      reject(error);
    });
  });
};
